package com.gitee.wsl.android.ext


import android.app.Notification
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.graphics.BitmapFactory
import android.graphics.drawable.Drawable
import android.os.Build
import android.widget.RemoteViews

import androidx.core.app.NotificationCompat
import androidx.core.app.Person
import androidx.annotation.RequiresApi
import com.gitee.wsl.android.ext.ApplicationInit.application
import com.gitee.wsl.android.ext.NotificationExt.DEFAULT_NOTIFICATION_ID
import com.gitee.wsl.android.ext.NotificationExt.defaultDownLoadNotificationBuilder
import com.gitee.wsl.android.ext.NotificationExt.defaultNotificationBuilder
import com.gitee.wsl.android.ext.NotificationExt.defaultServiceNotificationBuilder
import com.gitee.wsl.android.ext.NotificationExt.defaultWarnNotificationBuilder
import com.gitee.wsl.android.ext.NotificationExt.notificationServer
import com.gitee.wsl.android.ext.NotificationExt.notificationShow
import com.gitee.wsl.android.notification.IvyNotification
import com.gitee.wsl.android.notification.IvyNotificationChannel
import com.gitee.wsl.android.notification.NotificationService
import com.gitee.wsl.android.notification.notificationManager


object NotificationExt {

    const val DEFAULT_NOTIFICATION_ID = -5323
    const val DEFAULT_WARN_NOTIFICATION_ID=DEFAULT_NOTIFICATION_ID+1
    const val DEFAULT_DOWNLOAD_NOTIFICATION_ID=DEFAULT_NOTIFICATION_ID+2
    const val DEFAULT_SERVICE_NOTIFICATION_ID=DEFAULT_NOTIFICATION_ID+3
    const val DEFAULT_ALARM_NOTIFICATION_ID=DEFAULT_NOTIFICATION_ID+4

    val notificationServer by lazy {
        NotificationService(application)
    }

    private var notificationTheme = NotificationTheme()

    fun init(configTheme:(NotificationTheme)->Unit){
        configTheme(notificationTheme)
    }

    fun canShowNotifications(): Boolean {
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            notificationManager.areNotificationsEnabled()
        } else {
            true
        }
    }

    fun notificationShow(notification: IvyNotification){
        notificationServer.showNotification(notification)
    }

    inline fun notificationShow(notification: IvyNotification, configNotification: IvyNotification.()->Unit={}){
        configNotification(notification)
        notificationShow(notification)
    }


    fun defaultNotificationBuilder(context: Context, notificationId:Int=DEFAULT_NOTIFICATION_ID): IvyNotification {
       return  IvyNotification(
           context,
           notificationId,
           IvyNotificationChannel.DEFAULT_CHANNEL
       ).apply {
           notificationTheme.defaultColor?.let {
               color = it
               setColorized(true)
               setLights(it, 1000, 200)
           }
           priority = notificationTheme.defaultPriority
           setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
           notificationTheme.defaultSmallIcon?.let {
               setSmallIcon(it)
           }
           setAutoCancel(true)
       }
    }

    fun defaultWarnNotificationBuilder(context: Context, notificationId:Int= DEFAULT_WARN_NOTIFICATION_ID): IvyNotification {
        return  IvyNotification(
            context,
            notificationId,
            IvyNotificationChannel.DEFAULT_WARN_CHANNEL
        ).apply {
            getConfigColor(notificationTheme.warnColor)?.let {
                color =it
                setColorized(true)
                setLights(it, 1000, 200)
            }
            priority = notificationTheme.warnPriority
            setVisibility(NotificationCompat.VISIBILITY_PUBLIC)

            getConfigSmallIcon(notificationTheme.warnSmallIcon)?.let {
                setSmallIcon(it)
            }
            setAutoCancel(false)
        }
    }

    fun defaultDownLoadNotificationBuilder(context: Context, notificationId:Int= DEFAULT_DOWNLOAD_NOTIFICATION_ID): IvyNotification {
        return  IvyNotification(
            context,
            notificationId,
            IvyNotificationChannel.DEFAULT_DOWNLOAD_CHANNEL
        ).apply {
            getConfigColor(notificationTheme.downloadColor)?.let {
                color =it
                setColorized(true)
                setLights(it, 1000, 200)
            }
            priority = notificationTheme.downloadPriority
            setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
            getConfigSmallIcon(notificationTheme.downloadSmallIcon)?.let {
                setSmallIcon(it)
            }
            setAutoCancel(false)
        }
    }

    fun defaultServiceNotificationBuilder(context: Context, notificationId:Int= DEFAULT_SERVICE_NOTIFICATION_ID): IvyNotification {
        return  IvyNotification(
            context,
            notificationId,
            IvyNotificationChannel.DEFAULT_SERVER_CHANNEL
        ).apply {
            getConfigColor(notificationTheme.serviceColor)?.let {
                color =it
                setColorized(true)
                setLights(it, 1000, 200)
            }
            priority = notificationTheme.servicePriority
            setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
            getConfigSmallIcon(notificationTheme.serviceSmallIcon)?.let {
                setSmallIcon(it)
            }
            setOngoing(true)
            setAutoCancel(false)
        }
    }

    fun defaultAlarmNotificationBuilder(context: Context, notificationId:Int= DEFAULT_ALARM_NOTIFICATION_ID): IvyNotification {
        return  IvyNotification(
            context,
            notificationId,
            IvyNotificationChannel.DEFAULT_ALARM_CHANNEL
        ).apply {
            getConfigColor(notificationTheme.alarmColor)?.let {
                color =it
                setColorized(true)
                setLights(it, 1000, 200)
            }
            priority = notificationTheme.alarmPriority
            setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
            getConfigSmallIcon(notificationTheme.alarmSmallIcon)?.let {
                setSmallIcon(it)
            }
            setAutoCancel(false)
        }
    }

    private fun getConfigColor(baseColor: Int?, theme: NotificationTheme = notificationTheme):Int?{
        return baseColor?:theme.defaultColor
    }

    private fun getConfigSmallIcon(base: Int?,theme: NotificationTheme = notificationTheme):Int{
        return base?:theme.defaultSmallIcon
    }

}


class NotificationTheme{
    var defaultColor:Int? =null
    var defaultSmallIcon :Int = AppInfo.packageInfo.applicationInfo.icon
    var defaultPriority = NotificationCompat.PRIORITY_DEFAULT

    var warnColor :Int? =null
    var warnSmallIcon :Int? =null
    var warnPriority = NotificationCompat.PRIORITY_HIGH

    var downloadColor :Int? =null
    var downloadSmallIcon :Int? =null
    var downloadPriority = NotificationCompat.PRIORITY_HIGH

    var serviceColor :Int? =null
    var serviceSmallIcon :Int? =null
    var servicePriority = NotificationCompat.PRIORITY_HIGH

    var alarmColor :Int? =null
    var alarmSmallIcon :Int? =null
    var alarmPriority = NotificationCompat.PRIORITY_HIGH
}

interface NotificationBigScope{
    fun bigText(text:String)

    fun bigImage(imageId:Int)

    fun addBigRemoteView(packageName:String,layoutId:Int,viewConfig: RemoteViews.()->Unit)
}

interface NotificationMessageScope {
    fun addMessage( text:CharSequence, timestamp:Long,person: Person?)
}

interface NotificationInBoxScope {

    fun config(inboxStyle: NotificationCompat.InboxStyle.()->Unit)

    fun setBigContentTitle( title:CharSequence)
    fun setSummaryText( text:CharSequence)
    fun addLine( text:CharSequence)
    fun addLines(vararg text:CharSequence)

}

interface NotificationScope{
    fun config(callback: IvyNotification.()->Unit)

    fun actionTarget(targetClass: Class<*>,configIntent: PendingIntent.()->Unit={})

    fun actionTarget(intent: Intent)

    fun actionCancelToActivity(targetClass: Class<*>, configIntent: PendingIntent.()->Unit={})

    fun actionCancelToActivity(intent: Intent, configIntent: PendingIntent.()->Unit={})

    fun actionCancelToReceiver(targetClass: Class<*>,action:String, configIntent: PendingIntent.()->Unit={})

    fun actionCancelToReceiver(intent: Intent, configIntent: PendingIntent.()->Unit={})

    fun actionCancelToService(targetClass: Class<*>, configIntent: PendingIntent.()->Unit={})

    fun actionCancelToService(intent: Intent, configIntent: PendingIntent.()->Unit={})

    //fun channelCheck()

    fun addRemoteView(packageName:String,layoutId:Int,viewConfig: RemoteViews.()->Unit){
        val remoteViews = RemoteViews(packageName,layoutId)
        viewConfig(remoteViews)
        config{
            setCustomContentView(remoteViews)
        }
    }

    fun bigStyle(bigConfig: NotificationBigScope.()->Unit)

    fun messageStyle( user:Person,messageConfig: NotificationMessageScope.()->Unit)

    fun inBoxStyle( inBoxConfig: NotificationInBoxScope.()->Unit)
}



open class NotificationScopeImpl(val context: Context,val notification: IvyNotification):
    NotificationScope {


    override fun config(callback: IvyNotification.() -> Unit) {
        callback(notification)
    }

    override fun actionTarget(targetClass: Class<*>,configIntent: PendingIntent.()->Unit) {
        val tagIntent=context.pendingIntentActivity(targetClass,
            IntentExt.DEFAULT_REQUEST_CODE,configIntent)
        notification.setContentIntent(tagIntent)
    }

    override fun actionTarget(intent: Intent) {
        TODO("Not yet implemented")
    }

    private fun actionCancel(pendingIntent: PendingIntent){
        notification.setDeleteIntent(pendingIntent)
        notification.setAutoCancel(true)
    }

    override fun actionCancelToActivity(targetClass: Class<*>, configIntent: PendingIntent.() -> Unit) {
        val tagIntent=context.pendingIntentActivity(targetClass,
            IntentExt.DEFAULT_REQUEST_CODE,configIntent)
        actionCancel(tagIntent)
    }

    override fun actionCancelToActivity(intent: Intent, configIntent: PendingIntent.() -> Unit) {
        val tagIntent=context.pendingIntentActivity(intent,
            IntentExt.DEFAULT_REQUEST_CODE,configIntent)
        actionCancel(tagIntent)
    }

    override fun actionCancelToReceiver(
        targetClass: Class<*>,
        action:String,
        configIntent: PendingIntent.() -> Unit
    ) {
        val tagIntent=Intent(context,targetClass)
        tagIntent.action=action
        actionCancelToReceiver(tagIntent,configIntent)
    }

    override fun actionCancelToReceiver(intent: Intent, configIntent: PendingIntent.() -> Unit) {
        val tagIntent=context.pendingIntentBroadcast(intent,
            IntentExt.DEFAULT_REQUEST_CODE,configIntent)
        actionCancel(tagIntent)
    }

    override fun actionCancelToService(
        targetClass: Class<*>,
        configIntent: PendingIntent.() -> Unit
    ) {
        val tagIntent=context.pendingIntentService(targetClass,
            IntentExt.DEFAULT_REQUEST_CODE,configIntent)
        actionCancel(tagIntent)
    }

    override fun actionCancelToService(intent: Intent, configIntent: PendingIntent.() -> Unit) {
        val tagIntent=context.pendingIntentService(intent,
            IntentExt.DEFAULT_REQUEST_CODE,configIntent)
        actionCancel(tagIntent)
    }

    override fun bigStyle(bigConfig: NotificationBigScope.() -> Unit) {
       val scope=object: NotificationBigScope {
           override fun bigText(text: String) {
               notification.setStyle(NotificationCompat.BigTextStyle().bigText(text))
           }

           override fun bigImage(imageId: Int) {
               notification.setStyle(NotificationCompat.BigPictureStyle().bigPicture(BitmapFactory.decodeResource(notification.context.resources,imageId)))
           }

           override fun addBigRemoteView(
               packageName: String,
               layoutId: Int,
               viewConfig: RemoteViews.() -> Unit
           ) {
               val remoteViews = RemoteViews(packageName,layoutId)
               viewConfig(remoteViews)
               notification.setCustomBigContentView(remoteViews)
           }
       }
        bigConfig(scope)
    }


    @RequiresApi(Build.VERSION_CODES.P)
    override fun messageStyle(user: Person, messageConfig: NotificationMessageScope.() -> Unit) {
        val message = NotificationCompat.MessagingStyle(user)
        messageConfig(object: NotificationMessageScope {
            override fun addMessage(text: CharSequence, timestamp: Long, person: Person?) {
                message.addMessage(text,timestamp,person)
            }
        })
        notification.setStyle(message)
    }

    override fun inBoxStyle(inBoxConfig: NotificationInBoxScope.() -> Unit) {
       val inBox = NotificationCompat.InboxStyle()
        inBoxConfig(object : NotificationInBoxScope {
            override fun config(inboxStyle: NotificationCompat.InboxStyle.() -> Unit) {
                inboxStyle(inBox)
            }

            override fun setBigContentTitle(title: CharSequence) {
                inBox.setBigContentTitle(title)
            }

            override fun setSummaryText(text: CharSequence) {
                inBox.setSummaryText(text)
            }

            override fun addLine(text: CharSequence) {
               inBox.addLine(text)
            }

            override fun addLines(vararg text: CharSequence) {
                text.forEach {
                    addLine(it)
                }
            }
        })
        notification.setStyle(inBox)
    }

    /*override fun channelCheck() {
        val notificationManager =context.getSystemService(Context.NOTIFICATION_SERVICE) as? NotificationManager ?: return
        notificationManager.createNotificationChannel(notification.ivyChannel.create(context))
    }*/

}


inline fun Context.notificationBuilder(message:String, notificationId:Int=DEFAULT_NOTIFICATION_ID, configNotification: NotificationScope.()->Unit={}): IvyNotification {
    val notification = defaultNotificationBuilder(this,notificationId=notificationId)
    val scope= NotificationScopeImpl(this,notification)
    configNotification(scope)
    notification.setContentText(message)
    return notification
}

fun Context.buildNotification(message:String,notificationId:Int=DEFAULT_NOTIFICATION_ID,configNotification: NotificationScope.()->Unit={}):Notification{
    return notificationBuilder(message, notificationId, configNotification).build()
}

fun Context.notification(message:String,notificationId:Int=DEFAULT_NOTIFICATION_ID,configNotification: NotificationScope.()->Unit={}){
    notificationShow(notificationBuilder(message, notificationId, configNotification))
}

fun Context.notificationCanceled(notificationId:Int=DEFAULT_NOTIFICATION_ID){
    notificationServer.dismissNotification(notificationId)
}

interface NotificationWarnScope: NotificationScope {

}

class  NotificationWarnScopeImp(context: Context,notification: IvyNotification):
    NotificationScopeImpl(context,notification), NotificationWarnScope {

}

fun Context.notificationWarn(message:String, notificationId:Int= NotificationExt.DEFAULT_WARN_NOTIFICATION_ID, configNotification: NotificationWarnScope.()->Unit={}){
    val notification = defaultWarnNotificationBuilder(this,notificationId=notificationId)
    val scope= NotificationWarnScopeImp(this,notification)
    configNotification(scope)
    notification.setContentText(message)
    notificationShow(notification)
}

fun Context.notificationWarnCanceled(notificationId:Int= NotificationExt.DEFAULT_WARN_NOTIFICATION_ID){
    notificationCanceled(notificationId)
}

interface NotificationDownLoadScope: NotificationScope {

}

class  NotificationDownLoadScopeImp(context: Context,notification: IvyNotification):
    NotificationScopeImpl(context,notification), NotificationDownLoadScope {

}

fun Context.notificationDownLoad(message:String, notificationId:Int= NotificationExt.DEFAULT_DOWNLOAD_NOTIFICATION_ID, configNotification: NotificationDownLoadScope.()->Unit={}){
    val notification = defaultDownLoadNotificationBuilder(this,notificationId=notificationId)
    val scope= NotificationDownLoadScopeImp(this,notification)
    configNotification(scope)
    notification.setContentText(message)
    notificationShow(notification)
}

fun Context.notificationDownLoadCanceled(notificationId:Int= NotificationExt.DEFAULT_DOWNLOAD_NOTIFICATION_ID){
    notificationCanceled(notificationId)
}

interface NotificationServiceScope: NotificationScope {

}

class  NotificationServiceScopeImp(context: Context,notification:IvyNotification):
    NotificationScopeImpl(context,notification), NotificationServiceScope {

}

inline fun Context.notificationServiceBuilder(message:String, notificationId:Int=DEFAULT_NOTIFICATION_ID, configNotification: NotificationServiceScope.()->Unit={}): IvyNotification {
    val notification = defaultServiceNotificationBuilder(this,notificationId=notificationId)
    val scope= NotificationServiceScopeImp(this,notification)
    configNotification(scope)
    notification.setContentText(message)
    return notification
}

fun Context.buildNotificationService(message:String, notificationId:Int= NotificationExt.DEFAULT_SERVICE_NOTIFICATION_ID, configNotification: NotificationServiceScope.()->Unit={}):Notification{
    return notificationServiceBuilder(message, notificationId,configNotification).build()
}

fun Context.notificationService(message:String, notificationId:Int= NotificationExt.DEFAULT_SERVICE_NOTIFICATION_ID, configNotification: NotificationServiceScope.()->Unit={}){
    notificationShow(notificationServiceBuilder(message, notificationId,configNotification))
}

fun Context.notificationServiceCanceled(notificationId:Int= NotificationExt.DEFAULT_SERVICE_NOTIFICATION_ID){
    notificationCanceled(notificationId)
}

fun Notification.getBadgeIcon(context: Context, packageName: String): Drawable? {
    return smallIcon.loadDrawable(context)
}